package fsesl

import (
	"callsips/internal/model/account/asips"
	"callsips/internal/svc"
	"context"
	"errors"
	"fmt"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zusrut/fsock"
	"strconv"
	"strings"
	"time"
)

type EslSocket struct {
	svcCtx      *svc.ServiceContext
	esl         *fsock.FSock
	host        string
	port        int64
	pass        string
	collectLogs int
}

// 首次连接freeswitch
func (e *EslSocket) FirstConnectData() {
	evHandlers := map[string][]func(string, int){}
	evFilters := make(map[string][]string)

	tmpEsl, err := fsock.NewFSock(fmt.Sprintf("%s:%d", e.host, e.port), e.pass, 10, evHandlers, nil, evFilters, nil, 1)
	if err != nil {
		logx.Infof("首次连接freeswitch错误信息:%s", err.Error())
		return
	}

	defer tmpEsl.Disconnect()
	out, err := tmpEsl.SendBgapiCmd("switchname")
	if err != nil {
		logx.Infof("首次连接freeswitch错误信息:%s", err.Error())
		return
	}

	val := <-out
	logx.Infof("获取fs名称:%s", val)
	if strings.Contains(val, "-ERR") {
		return
	}

}

// 连接freeswitch
func (e *EslSocket) ESLConnectKeeper() {
	tenSecondsTick := time.Tick(10 * time.Second)
	e.Connect()
	go e.StartListenFSEvents()
	e.CollectAndSetESLDataESLData()
	for {
		select {
		case <-tenSecondsTick:
			if e.esl != nil && e.esl.Connected() {
				continue
			}

			logx.Error("Reconnecting to ESL...")
			e.Connect()
			if e.esl == nil || !e.esl.Connected() {
				continue
			}
			switchName, _ := e.SendBgapiCmd(CommandSwitchname)
			if switchName == "" {
				logx.Error("FS actual switchname is different from config file!!!")
				continue
			}

			go e.StartListenFSEvents()
			e.CollectAndSetESLDataESLData()
		}
	}
}

// 连接单个freeeswitch
func (e *EslSocket) Connect() {
	if e.esl != nil && e.esl.Connected() {
		return
	}

	var err error
	evFilters := make(map[string][]string)
	evFilters[EventName] = append(evFilters[EventName], NameChannelCreate)
	evFilters[EventName] = append(evFilters[EventName], NameChannelState)
	evFilters[EventName] = append(evFilters[EventName], NameChannelProgress)
	evFilters[EventName] = append(evFilters[EventName], NameChannelAnswer)
	evFilters[EventName] = append(evFilters[EventName], NameChannelBridge)
	evFilters[EventName] = append(evFilters[EventName], NameChannelHangup)
	evFilters[EventName] = append(evFilters[EventName], NameChannelHangupComplete)
	evFilters[EventName] = append(evFilters[EventName], NameChannelDestroy)
	evFilters[EventName] = append(evFilters[EventName], NameCustom)
	//evFilters[EventName] = append(evFilters[EventName], NamePublish)
	//evFilters[EventName] = append(evFilters[EventName], NameUnPublish)
	//evFilters[EventName] = append(evFilters[EventName], NameModuleUnload)
	//evFilters[EventName] = append(evFilters[EventName], NameModuleLoad)

	var channelHannder = NewChannelEventHandler(e.svcCtx)

	evHandlers := map[string][]func(string, int){
		NameChannelCreate:         {func(event string, id int) { channelHannder.ChannelCreateHandler(event, id) }},
		NameChannelProgress:       {func(event string, id int) { channelHannder.ChannelProgressHandler(event, id) }},
		NameChannelAnswer:         {func(event string, id int) { channelHannder.ChannelAnswerHandler(event, id) }},
		NameChannelBridge:         {func(event string, id int) { channelHannder.ChannelBridgeHandler(event, id) }},
		NameChannelHangup:         {func(event string, id int) { channelHannder.ChannelHangupHandler(event, id) }},
		NameChannelHangupComplete: {func(event string, id int) { channelHannder.ChannelHangupCompleteHandler(event, id) }},
		NameChannelDestroy:        {func(event string, id int) { channelHannder.ChannelDestroyHandler(event, id) }},
		NameCSRegister:            {func(event string, id int) { e.sofiaRegsHandler(event, id) }},
		NameCSUnregister:          {func(event string, id int) { e.sofiaRegsHandler(event, id) }},
		NameCSExpire:              {func(event string, id int) { e.sofiaRegsHandler(event, id) }},
		NameCSInfo:                {func(event string, id int) { e.sofiaRegsHandler(event, id) }},
	}

	logHandler := fsock.LogHandler{}

	if e.collectLogs > 0 && e.collectLogs < 11 {
		logHandler = fsock.LogHandler{Level: e.collectLogs, Handler: func(headers map[string]string, body string) { e.logHandlerFunc(headers, body) }}
	}

	e.esl, err = fsock.NewFSock(fmt.Sprintf("%s:%d", e.host, e.port), e.pass, 10, evHandlers, &logHandler, evFilters, nil, 1)
	if err != nil || e.esl == nil || !e.esl.Connected() {
		logx.Error("freeswitch connect fail")
	} else {

	}
}

// 开始监听
func (e *EslSocket) StartListenFSEvents() {
	if e.esl == nil || !e.esl.Connected() {
		return
	}
	err := e.esl.ReadEvents()
	if err != nil && e.esl != nil {
		_ = e.esl.Disconnect()
		logx.Error("Esl Disconnected.")
		return
	}
}

// 获取freeswitch数据
func (e *EslSocket) CollectAndSetESLDataESLData() {
	if e.esl == nil || !e.esl.Connected() {
		return
	}

	//可以从freeswitch获取数据
	logx.Info("可以从freeswitch获取数据")
}

// 处理错误日志
func (e *EslSocket) logHandlerFunc(headers map[string]string, body string) {
	logLine, err := strconv.Atoi(headers["Log-Line"])
	if err != nil {
		logLine = 0
	}
	logLevel, err := strconv.Atoi(headers["Log-Level"])
	if err != nil {
		logLevel = 0
	}

	textChannel, err := strconv.Atoi(headers["Text-Channel"])
	if err != nil {
		textChannel = 0
	}

	logx.Infof("logsChannel:%s,%s,%d,%d,%d,%s,%s", headers["Log-File"], headers["Log-Func"], logLine, logLevel, textChannel, headers["User-Data"], body)

}

// 发送命令到freeswitch
func (e *EslSocket) SendBgapiCmd(command string) (string, error) {
	if e.esl == nil || !e.esl.Connected() {
		return "", errors.New("no esl connection")
	}

	if command == "" {
		return "", errors.New("no command")
	}

	out, err := e.esl.SendBgapiCmd(command)
	if err != nil {
		return "", err
	}

	val := <-out
	if strings.Contains(val, "-ERR") {
		return val, errors.New(strings.TrimSpace(val))
	}

	return val, nil
}

// 处理注册和非主额
func (e *EslSocket) sofiaRegsHandler(event string, id int) {
	//logx.Info("-------通道资源销毁-------")

	var filterHeaders []string
	eventMap := fsock.FSEventStrToMap(event, filterHeaders)
	//logx.Info(eventMap)

	domainName := eventMap[HeaderFromHost]
	if domainName == "" {
		domainName = eventMap[HeaderHost]
	}

	userName := eventMap[HeaderFromUser]
	if userName == "" {
		userName = eventMap[HeaderUser]
	}

	logx.Infof("用户：%s,domain:%s,event:%s", userName, domainName, eventMap[EventSubclass])

	var eventName string = eventMap[EventSubclass]

	var (
		info *asips.AccountAsips
		err  error
	)

	if info, err = e.svcCtx.AccountSips.FindOneByUsername(context.Background(), userName); err != nil {
		logx.Infof("查询sip用户信息错误:%s", err.Error())
		return
	}

	var online int64 = 1
	if eventName == "sofia::register" { //注册成功
		online = 2
	} else if eventName == "sofia::unregister" { //注销注册
		online = 1
	} else if eventName == "sofia::expire" { //过期下线
		online = 1
	}

	logx.Infof("查询sip用户在线状态:%d=%d,eventName=%s", info.OnLine, online, eventName)
	if info.OnLine == online {
		return
	}

	if err = e.svcCtx.AccountSips.UpdateOneField(context.Background(), info, "on_line", online); err != nil {
		logx.Infof("更新sip用户信息错误:%s", err.Error())
		return
	}

	e.svcCtx.AccountSips.FindOne(context.Background(), info.Id)
	return
}

func NewEslSocket(svcCtx *svc.ServiceContext, host string, port int64, pass string) *EslSocket {
	return &EslSocket{
		svcCtx:      svcCtx,
		esl:         nil,
		host:        host,
		port:        port,
		pass:        pass,
		collectLogs: 3,
	}
}
